package com.own.component.common.util;

import javax.script.ScriptEngineManager;

/**
 * IntervalUtil
 *
 * @author chenxueli
 * @date 2022-06-15 03:14:15
 */
public class IntervalUtil {

    private static final String OR = " || ";
    private static final String AND = " && ";
    private static final String MATH_OR = "U";
    private static final String COMMA = ",";

    /**
     * 计算值
     *
     * @param value      需要计算的值
     * @param expression 区间表达式
     * @return 值信息
     * @author chenxueli
     * @date 2022-06-15 03:14:15
     */
    public static boolean calculate(String value, String expression) {
        var formula = convert(value, expression);
        var engine = new ScriptEngineManager().getEngineByName("JavaScript");
        try {
            return (Boolean) engine.eval(formula);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 验证表达式是否正确
     *
     * @param expression 区间表达式
     * @return 是否正确
     * @author chenxueli
     * @date 2022-06-15 03:14:15
     */
    public static boolean check(String expression) {
        try {
            var formula = convert("0", expression);
            var engine = new ScriptEngineManager().getEngineByName("JavaScript");
            engine.eval(formula);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 将所有阀值区间转化为公式
     * [0,20] => value <= 20 && value >= 0
     * (0,20] => value <= 20 && value > 0
     * (0,20]U[30,40] => (value <= 20 && value > 0) || (value <= 40 && value >= 30)
     *
     * @param value      需要计算的值
     * @param expression 区间表达式
     * @return 公式信息
     * @author chenxueli
     * @date 2022-06-15 03:14:15
     */
    public static String convert(String value, String expression) {
        var builder = new StringBuilder();
        var array = expression.split(MATH_OR);
        for (var limit : array) {
            builder.append("(").append(convertSingle(value, limit)).append(")").append(OR);
        }
        var string = builder.toString();
        var index = string.lastIndexOf(OR);
        return string.substring(0, index);
    }

    /**
     * 将整个阀值区间转化为公式
     * 20] => value <= 20
     * (0,20] => value <= 20 && value > 0
     *
     * @param value      需要计算的值
     * @param expression 区间表达式
     * @return 公式信息
     * @author chenxueli
     * @date 2022-06-15 03:14:15
     */
    private static String convertSingle(String value, String expression) {
        var builder = new StringBuilder();
        var array = expression.split(COMMA);
        for (var halfExpression : array) {
            builder.append(convertHalf(halfExpression, value)).append(AND);
        }
        var string = builder.toString();
        var index = string.lastIndexOf(AND);
        return string.substring(0, index);
    }

    /**
     * 将半个阀值区间转化为公式
     * 145) => value < 145
     * ≥80% => value >= 0.8
     * [130 => value >= 130
     * <80% => value < 0.8
     *
     * @param halfExpression 表达式
     * @param value          需要计算的值
     * @return 公式信息
     * @author chenxueli
     * @date 2022-06-15 03:14:15
     */
    @SuppressWarnings("all")
    private static String convertHalf(String halfExpression, String value) {
        halfExpression = halfExpression.trim();
        // 包含无穷大则不需要公式
        if (halfExpression.contains("∞")) {
            return "1 == 1";
        }
        var formula = new StringBuilder();
        String data;
        String opera;
        // 表示判断方向（如>）在前面 如：≥80%
        if (halfExpression.matches("^([<>≤≥\\[\\(]{1}(-?\\d+.?\\d*\\%?))$")) {
            opera = halfExpression.substring(0, 1);
            data = halfExpression.substring(1);
        }
        // [130、145)
        else {
            opera = halfExpression.substring(halfExpression.length() - 1);
            data = halfExpression.substring(0, halfExpression.length() - 1);
        }
        var tempValue = dealPercent(data);
        formula.append(value).append(" ").append(opera).append(" ").append(tempValue);
        // 转化特定字符
        return formula.toString()
                .replace("[", ">=")
                .replace("(", ">")
                .replace("]", "<=")
                .replace(")", "<")
                .replace("≤", "<=")
                .replace("≥", ">=");
    }

    /**
     * 去除百分号，转为小数
     *
     * @param str 可能含百分号的数字
     * @return 数值信息
     * @author chenxueli
     * @date 2022-06-15 03:14:15
     */
    private static double dealPercent(String str) {
        if (str.contains("%")) {
            str = str.substring(0, str.length() - 1);
            return Double.parseDouble(str) / 100;
        }
        return Double.parseDouble(str);
    }

}
